/********************************************************
 * Filename: TclNamespaceView.java
 * Author: LMU
 * Program: TUnit
 * Description: Creates the tree view associated with
 * the Namespace Explorer.  
 * Revision History:
 * 20060904: Initial revision.  Added header later.  
 * 20061013: Did a little refactoring.  
 * *****************************************************/

package edu.lmu.cs.tUnit.view.treeviewer;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Iterator;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.ViewPart;

import edu.lmu.cs.tUnit.log.TUnitLog;
import edu.lmu.cs.tUnit.plugin.TUnitPlugin;
import edu.lmu.cs.tUnit.view.model.Model;
import edu.lmu.cs.tUnit.view.model.TclNamespace;
import edu.lmu.cs.tUnit.view.model.TclProcedure;

/**
 * The Namespace Explorer view
 * @see ViewPart
 */
public class TclNamespaceView extends ViewPart {
	protected TreeViewer treeViewer;
	protected Text text;
	protected TclNamespaceLabelProvider labelProvider;
	protected TclNamespaceContentProvider contentProvider;
	
	protected Action refreshAction;
	protected Action doubleClickAction;
	
	protected TclNamespace root;
	
	/**
	 * The constructor.
	 */
	public TclNamespaceView() {
	}
	
	/**
	 * Return the label provider
	 */
	public TclNamespaceLabelProvider getLabelProvider() {
		return labelProvider;
	}
	
	/**
	 * Return the content provider
	 */
	public TclNamespaceContentProvider getContentProvider() {
		return contentProvider;
	}

	/*
	 * @see IWorkbenchPart#createPartControl(Composite)
	 */
	public void createPartControl(Composite parent) {
		/* Create a grid layout object so the text and treeviewer
		 * are layed out the way I want. 
		 */
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		layout.verticalSpacing = 2;
		layout.marginWidth = 0;
		layout.marginHeight = 2;
		parent.setLayout(layout);
		
		/* Create a "label" to display information in. I'm
		 * using a text field instead of a lable so you can
		 * copy-paste out of it. 
		 */
		text = new Text(parent, SWT.READ_ONLY | SWT.SINGLE | SWT.BORDER);
		
		// layout the text field above the treeviewer
		GridData layoutData = new GridData();
		layoutData.grabExcessHorizontalSpace = true;
		layoutData.horizontalAlignment = GridData.FILL;
		text.setLayoutData(layoutData);
		
		// Create the tree viewer as a child of the composite parent
		contentProvider = new TclNamespaceContentProvider();
		treeViewer = new TreeViewer(parent);
		treeViewer.setContentProvider(contentProvider);
		labelProvider = new TclNamespaceLabelProvider();
		treeViewer.setLabelProvider(labelProvider);
		treeViewer.setUseHashlookup(true);
		
		// layout the tree viewer below the text field
		layoutData = new GridData();
		layoutData.grabExcessHorizontalSpace = true;
		layoutData.grabExcessVerticalSpace = true;
		layoutData.horizontalAlignment = GridData.FILL;
		layoutData.verticalAlignment = GridData.FILL;
		treeViewer.getControl().setLayoutData(layoutData);
		
		// Create menu, toolbars, filters, sorters.
		createActions();
		createToolbar();
		hookListeners();
		
		try {
			treeViewer.setInput(getInitalInput());
		} catch (IOException e) {
			TUnitLog.logError("Could not set the Namespace Explorer input.", e);
		}
		treeViewer.expandAll();
	}

	protected void hookListeners() {
		treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent event) {
				// if the selection is empty clear the label
				if(event.getSelection().isEmpty()) {
					text.setText("");
					return;
				}
				
				if(event.getSelection() instanceof IStructuredSelection) {
					IStructuredSelection selection = (IStructuredSelection)event.getSelection();
					StringBuffer toShow = new StringBuffer();
					for (Iterator iterator = selection.iterator(); iterator.hasNext();) {
						Object domain = (Model) iterator.next();
						String value = labelProvider.getText(domain);
						toShow.append(value);
						toShow.append(", ");
					}
					
					// remove the trailing comma space pair
					if(toShow.length() > 0) {
						toShow.setLength(toShow.length() - 2);
					}
					text.setText(toShow.toString());
				}
			}
		});
		
		treeViewer.addDoubleClickListener(new IDoubleClickListener () {
			public void doubleClick(DoubleClickEvent event) {
				doubleClickAction.run();
			}
		});
	}
	
	protected void createActions() {		
		refreshAction = new Action("Refresh") {
			public void run() {
				try {
					refreshPage();
				} catch (IOException e) {
					TUnitLog.logError("Could not refresh Namespace Explorer properly.", e);
				}
			}			
		};
		refreshAction.setToolTipText("Refresh");
		URL SAMPLE = TUnitPlugin.getDefault().getBundle().getEntry("/icons/refresh.gif");
		refreshAction.setImageDescriptor(ImageDescriptor.createFromURL(SAMPLE));
		
		doubleClickAction = new Action() {
			public void run() {
				ISelection selection = treeViewer.getSelection();
				Object obj = ((IStructuredSelection)selection).getFirstElement();
				
				if(obj instanceof TclProcedure) {
					TclProcedure temp = (TclProcedure) obj;
					String openFile = temp.getFileName();	
					IProject tempProject = temp.getProject();
					IWorkbenchPage page =
						PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
					try {
						IDE.openEditor(page, tempProject.getFile(openFile), true);
					} catch (PartInitException e) {
						TUnitLog.logError("Could not open editor.", e);
					}
				}
			}
		};
	}
	
	/**
	 *  Refresh Namespace Explorer
	 *
	*/
	public void refreshPage() throws IOException{
		root = new TclNamespace();
		IWorkbench wb = PlatformUI.getWorkbench();
		if(wb == null) {
			treeViewer.setInput(root);
			treeViewer.getTree().setRedraw(true);
			return;
		}
		
		IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
		if(win == null) {
			treeViewer.setInput(root);
			treeViewer.getTree().setRedraw(true);
			return;
		}
		
		IWorkbenchPage page = win.getActivePage();
		if(page == null) {
			treeViewer.setInput(root);
			treeViewer.getTree().setRedraw(true);
			return;
		}
		
		//the current selection in the navigator view
		ISelection selection = page.getSelection(IPageLayout.ID_RES_NAV);
		if(selection == null) {
			treeViewer.setInput(root);
			treeViewer.getTree().setRedraw(true);
			return;
		}
		
		IResource res = extractSelection(selection);
		if(res == null) {
			treeViewer.setInput(root);
			treeViewer.getTree().setRedraw(true);
			return;
		}
		
		IProject project = res.getProject();
		if(project == null) {
			treeViewer.setInput(root);
			treeViewer.getTree().setRedraw(true);
			return;
		}
				
		if(!project.isOpen()) {
			treeViewer.setInput(root);
			treeViewer.getTree().setRedraw(true);
			return;
		}
		
		createExplorer(project);
		treeViewer.setInput(root);
		treeViewer.expandAll();
		treeViewer.getTree().setRedraw(true);		
	}
	
	protected void createToolbar() {
		IToolBarManager toolbarManager = getViewSite().getActionBars().getToolBarManager();
		toolbarManager.add(refreshAction);
	}
	
	
	public TclNamespace getInitalInput() throws IOException {		
		root = new TclNamespace();

		IWorkbench wb = PlatformUI.getWorkbench();
		if(wb == null)
			return root;
		
		IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
		if(win == null)
			return root;
		
		IWorkbenchPage page = win.getActivePage();
		if(page == null)
			return root;
		
		//the current selection in the navigator view
		ISelection selection = page.getSelection(IPageLayout.ID_RES_NAV);
		if(selection == null)
			return root;
		
		IResource res = extractSelection(selection);
		if(res == null)
			return root;
		
		IProject project = res.getProject();
		if(project == null)
			return root;
		
		if(!project.isOpen())
			return root;
		
		createExplorer(project);
		return root;
	}

	/**
	 * Create Namespace Explorer from the tclIndex file
	 * @param project the project to create NamespaceExplorer from
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private void createExplorer(IProject project) throws FileNotFoundException, IOException {
		IPath path = project.getLocation();
		File file = path.toFile();
		String filePath = file.getAbsolutePath();
		String[] fileList = file.list();
		for(int i = 0; i < fileList.length; i++) {
			File tempFile = new File(filePath + "/" + fileList[i]);
			if(tempFile.isDirectory()) {
				tempFile = new File(filePath + "/" + fileList[i] + "/tclIndex");
				if(tempFile.exists()) {
					TclNamespace temp = new TclNamespace(fileList[i]);
					root.add(temp);
					FileInputStream init = new FileInputStream(tempFile);
					BufferedReader in = new BufferedReader(new InputStreamReader(init));
					String thisLine = "";
					while((thisLine = in.readLine()) != null) {
						if(thisLine.startsWith("set auto_index")) {;
							int startIndex = thisLine.indexOf('(');
							int endIndex = thisLine.indexOf(')');
							String procedureName = thisLine.substring(startIndex+1, endIndex);
							startIndex = thisLine.indexOf("$dir");
							endIndex = thisLine.indexOf(".tcl");
							String pathName = "/" + fileList[i] + "/" + thisLine.substring(startIndex+5, endIndex+4);
							temp.add(new TclProcedure(procedureName, pathName, project));
						}
					}
					in.close();
				}
			}
		}
	}
	
	public IResource extractSelection(ISelection sel) {
		if (!(sel instanceof IStructuredSelection))
			return null;
		IStructuredSelection ss = (IStructuredSelection)sel;
		Object element = ss.getFirstElement();
		if (element instanceof IResource)
			return (IResource) element;
		if (!(element instanceof IAdaptable))
			return null;
		IAdaptable adaptable = (IAdaptable)element;
		Object adapter = adaptable.getAdapter(IResource.class);
		return (IResource) adapter;
	}

	/*
	 * @see IWorkbenchPart#setFocus()
	 */
	public void setFocus() {}

}
